home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The CICA Windows Explosion!
/
The CICA Windows Explosion! - Disc 2.iso
/
programr
/
dpmigcc5.zip
/
RSX
/
SOURCE
/
TERMIO.C
< prev
next >
Wrap
C/C++ Source or Header
|
1994-12-12
|
13KB
|
534 lines
/*****************************************************************************
* FILE: termio.c *
* *
* DESC: *
* - ioctl() terminal functions *
* *
* Copyright (C) 1993,1994 *
* Rainer Schnitker, Heeper Str. 283, 33607 Bielefeld *
* email: rainer@mathematik.uni-bielefeld.de *
* *
*****************************************************************************/
#include <ctype.h>
#include "DPMI.H"
#include "RMLIB.H"
#include "SIGNALS.H"
#include "PROCESS.H"
#include "START32.H"
#include "COPY32.H"
#include "RSX.H"
#include "EXCEP32.H"
#include "TERMIO.H"
#include "DOSERRNO.H"
#include "PRINTF.H"
/*
* Sourcecode based on Linux v1.1
*
* linux/kernel/tty_io.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
#define _O_FLAG(tty,X) ((tty)->termios->c_oflag & (unsigned long)(X))
#define _C_FLAG(tty,X) ((tty)->termios->c_cflag & (unsigned long)(X))
#define _L_FLAG(tty,X) ((tty)->termios->c_lflag & (unsigned long)(X))
#define _I_FLAG(tty,X) ((tty)->termios->c_iflag & (unsigned long)(X))
#define L_ISIG(tty) _L_FLAG((tty),ISIG)
#define L_ICANON(tty) _L_FLAG((tty),ICANON)
#define L_XCASE(tty) _L_FLAG((tty),XCASE)
#define L_ECHO(tty) _L_FLAG((tty),ECHO)
#define L_ECHOE(tty) _L_FLAG((tty),ECHOE)
#define L_ECHOK(tty) _L_FLAG((tty),ECHOK)
#define L_ECHONL(tty) _L_FLAG((tty),ECHONL)
#define L_NOFLSH(tty) _L_FLAG((tty),NOFLSH)
#define L_IDEFAULT _L_FLAG((tty),IDEFAULT)
#define I_IUCLC(tty) _I_FLAG((tty),IUCLC)
#define I_INLCR(tty) _I_FLAG((tty),INLCR)
#define I_ICRNL(tty) _I_FLAG((tty),ICRNL)
#define I_IGNCR(tty) _I_FLAG((tty),IGNCR)
#define I_IXON(tty) _I_FLAG((tty),IXON)
#define I_IXANY(tty) _I_FLAG((tty),IXANY)
#define I_ISTRIP(tty) _I_FLAG((tty),ISTRIP)
#define I_IDELETE(tty) _I_FLAG((tty),IDELETE)
#define INTR_CHAR(tty) ((tty)->termios->c_cc[VINTR])
#define QUIT_CHAR(tty) ((tty)->termios->c_cc[VQUIT])
#define ERASE_CHAR(tty) ((tty)->termios->c_cc[VERASE])
#define KILL_CHAR(tty) ((tty)->termios->c_cc[VKILL])
#define EOF_CHAR(tty) ((tty)->termios->c_cc[VEOF])
#define EOL_CHAR(tty) ((tty)->termios->c_cc[VEOL])
#define __DISABLED_CHAR '\0'
#define INC(a) ((a) = ((a)+1) & (TTY_BUF_SIZE-1))
#define DEC(a) ((a) = ((a)-1) & (TTY_BUF_SIZE-1))
#define EMPTY(a) ((a)->head == (a)->tail)
#define LEFT(a) (((a)->tail-(a)->head-1)&(TTY_BUF_SIZE-1))
#define LAST(a) ((a)->buf[(TTY_BUF_SIZE-1)&((a)->head-1)])
#define FULL(a) (!LEFT(a))
#define CHARS(a) (((a)->head-(a)->tail)&(TTY_BUF_SIZE-1))
#define TTY_BUF_SIZE 128
struct tty_queue {
int head;
int tail;
char buf[TTY_BUF_SIZE];
};
struct tty_struct {
struct termio *termios;
int canon_data;
int canon_head;
unsigned int erasing:1;
unsigned int lnext:1;
unsigned long secondary_flags[TTY_BUF_SIZE / (sizeof(long))];
struct tty_queue secondary;
};
struct termio __termios =
{
BRKINT | ICRNL | IXON | IXANY, /* iflag */
0, /* oflag */
B9600 | CS8 | CREAD | HUPCL, /* cflag */
ISIG | ICANON | ECHO | ECHOE | ECHOK | IDEFAULT, /* lflag */
0, /* line */
{ 003, 034, 010, 025, 004, 000, 006, 001 } /* c_cc */
/* INTR, QUIT,ERASE, KILL, EOF , EOL , VMIN, VTIME */
/* C-C , C-\ , C-H , C-U , C-D , EOL , VMIN, VTIME */
};
struct tty_struct __tty =
{
&__termios,
0,
0,
0,
0,
0,
0
};
static char control_c;
static unsigned long timeout;
/* flush keyboard buffer */
static void keyboard_flush(void)
{
while (rm_bios_read_keybrd(kready))
rm_bios_read_keybrd(kread);
}
/* read a key ; extended = 0,next call scan-code */
static int keyboard_read()
{
static int next_key = 0;
int key, scan, ascii;
if (next_key) {
ascii = next_key;
next_key = 0;
} else {
if (!rm_bios_read_keybrd(kready)) {
if (timeout)
if (timeout <= time_tic)
timeout = 0;
return -1;
}
key = rm_bios_read_keybrd(kread);
ascii = key & 0xff;
scan = key >> 8;
if (ascii == 0xE0)
ascii = 0;
if (ascii == 0)
next_key = scan;
}
return ascii;
}
int set_bit(int nr, void *vaddr)
{
long mask;
int retval;
unsigned long *addr = vaddr;
addr += nr >> 5;
mask = 1L << (nr & 0x1f);
retval = (mask & *addr) != 0;
*addr |= mask;
return retval;
}
int clear_bit(int nr, void *vaddr)
{
long mask;
int retval;
unsigned long *addr = vaddr;
addr += nr >> 5;
mask = 1L << (nr & 0x1f);
retval = (mask & *addr) != 0;
*addr &= ~mask;
return retval;
}
static void put_tty_queue(unsigned char c, struct tty_queue * queue)
{
int head = (queue->head + 1) & (TTY_BUF_SIZE - 1);
if (head != queue->tail) {
queue->buf[queue->head] = c;
queue->head = head;
}
}
static int get_tty_queue(struct tty_queue * queue)
{
int result = -1;
if (queue->tail != queue->head) {
result = queue->buf[queue->tail];
INC(queue->tail);
}
return result;
}
static void flush_input(struct tty_queue * queue)
{
keyboard_flush();
queue->head = queue->tail;
}
#define TTY_READ_FLUSH(tty) copy_to_cooked(tty)
static char next_line[2] = "\r\n";
int output;
static int opost(unsigned char c, struct tty_struct * tty)
{
if ((c == 10) && (L_ECHO(tty) || (L_ICANON(tty) && L_ECHONL(tty))))
rm_write(output, next_line, sizeof(next_line));
else if (L_ECHO(tty))
rm_write(output, &c, 1);
return 1;
}
static void echo_char(unsigned char c, struct tty_struct * tty)
{
if (iscntrl(c) && c != '\t') {
opost('^', tty);
opost((unsigned char)(c ^ 0100), tty);
} else
opost((unsigned char) c, tty);
}
static void eraser(unsigned char c, struct tty_struct * tty)
{
enum {
ERASE, WERASE, KILL
} kill_type;
int seen_alnums;
if (tty->secondary.head == tty->canon_head) {
/* opost('\a', tty); *//* what do you think? */
return;
}
if (c == ERASE_CHAR(tty))
kill_type = ERASE;
else {
if (!L_ECHO(tty)) {
tty->secondary.head = tty->canon_head;
return;
}
if (!L_ECHOK(tty)) {
tty->secondary.head = tty->canon_head;
if (tty->erasing) {
opost('/', tty);
tty->erasing = 0;
}
echo_char(KILL_CHAR(tty), tty);
/* Add a newline if ECHOK is on */
if (L_ECHOK(tty))
opost('\n', tty);
return;
}
kill_type = KILL;
}
seen_alnums = 0;
while (tty->secondary.head != tty->canon_head) {
c = LAST(&tty->secondary);
DEC(tty->secondary.head);
if (L_ECHO(tty)) {
if (!L_ECHOE(tty)) {
echo_char(ERASE_CHAR(tty), tty);
}
}
if (kill_type == ERASE)
break;
}
if (tty->erasing && tty->secondary.head == tty->canon_head) {
opost('/', tty);
tty->erasing = 0;
}
}
static void copy_to_cooked(struct tty_struct * tty)
{
char c;
for (;;) {
if (! LEFT(&tty->secondary))
break;
c = (char) keyboard_read();
if (c < 0)
break;
if (I_ISTRIP(tty))
c &= 0x7f;
if (!tty->lnext) {
if (c == '\r') {
if (I_IGNCR(tty))
continue;
if (I_ICRNL(tty))
c = '\n';
} else if (c == '\n' && I_INLCR(tty))
c = '\r';
}
if (I_IUCLC(tty))
c = (char) tolower(c);
if (I_IDELETE(tty) && c == 8)
c = 127;
if (c == __DISABLED_CHAR)
tty->lnext = 1;
if (L_ICANON(tty) && !tty->lnext) {
if ((unsigned char)c == ERASE_CHAR(tty) ||
(unsigned char)c == KILL_CHAR(tty)) {
eraser(c, tty);
continue;
}
}
if (L_ISIG(tty) && !tty->lnext) {
if ((unsigned char)c == INTR_CHAR(tty)) {
control_c = 1;
send_signal(npz, SIGINT);
flush_input(&tty->secondary);
return;
}
if ((unsigned char) c == QUIT_CHAR(tty)) {
control_c = 1;
send_signal(npz, SIGQUIT);
flush_input(&tty->secondary);
return;
}
}
if (tty->erasing) {
opost('/', tty);
tty->erasing = 0;
}
if (c == '\n' && !tty->lnext) {
if (L_ECHO(tty) || (L_ICANON(tty) && L_ECHONL(tty)))
opost('\n', tty);
} else if (L_ECHO(tty)) {
/* Don't echo the EOF char in canonical mode. Sun
handles this differently by echoing the char and
then backspacing, but that's a hack. */
if ((unsigned char) c != EOF_CHAR(tty) || !L_ICANON(tty) ||
tty->lnext) {
echo_char(c, tty);
}
}
if (c == '\377' && (c != (char)EOF_CHAR(tty) || !L_ICANON(tty) || tty->lnext))
put_tty_queue(c, &tty->secondary);
if (L_ICANON(tty) && !tty->lnext &&
(c == '\n' || c == (char)EOF_CHAR(tty) ||
c == (char)EOL_CHAR(tty) )) {
if (c == (char)EOF_CHAR(tty))
c = __DISABLED_CHAR;
set_bit(tty->secondary.head, &tty->secondary_flags);
put_tty_queue(c, &tty->secondary);
tty->canon_head = tty->secondary.head;
tty->canon_data++;
} else
put_tty_queue(c, &tty->secondary);
tty->lnext = 0;
}
}
static int input_available_p(struct tty_struct * tty)
{
/* Avoid calling TTY_READ_FLUSH unnecessarily. */
if (L_ICANON(tty) ? tty->canon_data : !EMPTY(&tty->secondary))
return 1;
/* Shuffle any pending data down the queues. */
TTY_READ_FLUSH(tty);
if (L_ICANON(tty) ? tty->canon_data : !EMPTY(&tty->secondary))
return 1;
return 0;
}
static int read_chan(struct tty_struct * tty, WORD ds, long buf, int nr)
{
int c;
long b = buf;
int minimum, time;
int retval = 0;
control_c = 0;
if (L_ICANON(tty)) {
minimum = time = 0;
timeout = (unsigned long) -1;
} else {
time = tty->termios->c_cc[VTIME] * 10;
minimum = tty->termios->c_cc[VMIN];
if (minimum)
timeout = 0xffffffff;
else {
if (time)
timeout = (unsigned long) time / 55L + time_tic;
else
timeout = 0;
time = 0;
minimum = 1;
}
}
for (;;) {
if (!input_available_p(tty)) {
if (!timeout)
break;
if (npz->filp[0]->f_flags & FCNTL_NDELAY) {
retval = -EMX_EAGAIN;
break;
}
continue;
}
for (;;) {
int eol;
if (EMPTY(&tty->secondary))
break;
eol = clear_bit(tty->secondary.tail, &tty->secondary_flags);
c = tty->secondary.buf[tty->secondary.tail];
if (!nr) {
/* Gobble up an immediately following EOF if
there is no more room in buf (this can
happen if the user "pushes" some characters
using ^D). This prevents the next read()
from falsely returning EOF. */
if (eol) {
if (c == __DISABLED_CHAR) {
tty->canon_data--;
INC(tty->secondary.tail);
} else {
set_bit(tty->secondary.tail,
&tty->secondary_flags);
}
}
break;
}
INC(tty->secondary.tail);
if (eol) {
if (--tty->canon_data < 0) {
printf("read_chan: canon_data < 0!\n");
tty->canon_data = 0;
}
if (c == __DISABLED_CHAR)
break;
put_user_byte(ds, b, (char)c);
b++;
nr--;
break;
}
put_user_byte(ds, b++, (char)c);
nr--;
}
if ((int) (long) (b - buf >= minimum) || !nr)
break;
if (time)
timeout = time + time_tic;
}
timeout = 0;
return (int) ((b - buf) ? b - buf : retval);
}
int termio_read(unsigned ds, unsigned long buf, int count)
{
struct tty_struct *tty = &__tty;
output = npz->filp[1]->f_doshandle;
if (!tty)
return -EMX_EIO;
return read_chan(tty, ds, buf, count);
}
static DWORD do_fionread()
{
struct tty_struct *tty = &__tty;
TTY_READ_FLUSH(tty);
return (DWORD) (CHARS(&tty->secondary));
}
int kbd_ioctl(unsigned cmd, unsigned long termio_arg)
{
struct tty_struct *tty = &__tty;
switch (cmd) {
case TCGETA:
if (verify_illegal(npz, termio_arg, sizeof(struct termio)))
return -EMX_EINVAL;
cpy16_32(npz->data32sel, termio_arg,
tty->termios, sizeof(struct termio));
return 0;
case TCSETAF:
flush_input(&tty->secondary);
/* fall through */
case TCSETAW:
case TCSETA:
if (verify_illegal(npz, termio_arg, sizeof(struct termio)))
return -EMX_EINVAL;
cpy32_16(npz->data32sel, termio_arg,
tty->termios, sizeof(struct termio));
flush_input(&tty->secondary);
/*if (!L_IDEFAULT) */
npz->p_flags |= PF_TERMIO; /* enable termio */
/*
else
npz->p_flags &= ~PF_TERMIO;
*/
return 0;
case TCFLSH:
/* if (termio_arg == 0) */
flush_input(&tty->secondary);
return 0;
case FIONREAD:
if (verify_illegal(npz, termio_arg, sizeof(long)))
return -EMX_EINVAL;
store32(npz->data32sel, termio_arg, do_fionread());
return 0;
default:
return -EMX_EINVAL;
}
}